Hướng dẫn học JavaScript từ cơ bản: Biến, Hàm, Array và Object dành cho người mới bắt đầu
JavaScript là ngôn ngữ lập trình để làm website tương tác. Với JavaScript, bạn có thể:
Đặt tên biến rõ ràng giúp bạn và người khác dễ hiểu code. Giống như đặt tên file, tên biến phải nói lên nó chứa gì.
// ✅ Đặt tên biến ĐÚNG - dễ hiểu
const userName = 'john'; // ✓ Rõ ràng: tên của user
const userAge = 25; // ✓ Rõ ràng: tuổi của user
const isLoggedIn = true; // ✓ Rõ ràng: đã đăng nhập chưa
// ❌ Đặt tên biến SAI - khó hiểu
const u = 'john'; // ❌ u là gì? Không rõ
const x = 25; // ❌ x là gì? Không rõ
const flag = true; // ❌ flag gì? Không rõ
// ✅ Quy tắc đặt tên
// - Chữ cái đầu viết thường
// - Từ thứ 2 trở đi viết hoa chữ cái đầu (camelCase)
const firstName = 'John'; // first + Name
const lastName = 'Doe'; // last + Name
const fullName = 'John Doe'; // full + Name
const phoneNumber = '0123456789'; // phone + Number
// ✅ Tên hằng số - viết HOA tất cả
const MAX_AGE = 100; // Tuổi tối đa
const MIN_SCORE = 0; // Điểm tối thiểu
JavaScript có 3 từ khóa để tạo biến: const, let và var. Chúng ta sẽ học const và let vì chúng dễ hiểu và an toàn hơn.
// ✅ Dùng CONST cho giá trị không thay đổi
const myName = 'John'; // Tên không đổi
const myAge = 20; // Tuổi hiện tại
const PI = 3.14; // Số pi không đổi
// ✅ Dùng LET cho giá trị sẽ thay đổi
let score = 0; // Điểm sẽ tăng giảm
let currentLevel = 1; // Level sẽ thay đổi
let isGameOver = false; // Trạng thái game
// ✅ Ví dụ thay đổi giá trị với LET
score = score + 10; // Tăng điểm
currentLevel = currentLevel + 1; // Lên level
isGameOver = true; // Game kết thúc
// ❌ KHÔNG thể thay đổi CONST
// myName = 'Jane'; // ❌ Lỗi! Không thể thay đổi const
// ✅ Tạo từng biến trên 1 dòng (dễ đọc)
const userName = 'Alice';
const userEmail = 'alice@email.com';
const userPhone = '0123456789';
// ❌ Tạo nhiều biến trên 1 dòng (khó đọc)
const a = 1, b = 2, c = 3; // Khó hiểu a, b, c là gì
Function (hàm) là một đoạn code có thể tái sử dụng. Giống như một chiếc máy: bạn cho nguyên liệu vào, máy xử lý và cho ra kết quả.
// ✅ Cách tạo function đơn giản
// Cú pháp: function tênFunction() { code }
// Function không có tham số (parameter)
function sayHello() {
console.log('Xin chào!');
}
// Gọi function
sayHello(); // In ra: Xin chào!
// Function có tham số
function greetUser(userName) {
console.log('Xin chào ' + userName + '!');
}
// Gọi function với tham số
greetUser('John'); // In ra: Xin chào John!
greetUser('Mary'); // In ra: Xin chào Mary!
// Function có return (trả về giá trị)
function addTwoNumbers(a, b) {
const sum = a + b;
return sum; // Trả về kết quả
}
// Sử dụng function có return
const result = addTwoNumbers(5, 3);
console.log(result); // In ra: 8
// Function tính diện tích hình chữ nhật
function calculateArea(width, height) {
const area = width * height;
return area;
}
const myArea = calculateArea(10, 5);
console.log('Diện tích:', myArea); // In ra: Diện tích: 50
// ❌ Không dùng function - Code lặp lại nhiều lần
const student1Score = 85;
const student1Grade = student1Score >= 90 ? 'A' : student1Score >= 80 ? 'B' : 'C';
console.log('Học sinh 1 được điểm:', student1Grade);
const student2Score = 92;
const student2Grade = student2Score >= 90 ? 'A' : student2Score >= 80 ? 'B' : 'C';
console.log('Học sinh 2 được điểm:', student2Grade);
// ✅ Dùng function - Code ngắn gọn, dễ sử dụng
function calculateGrade(score) {
if (score >= 90) {
return 'A';
} else if (score >= 80) {
return 'B';
} else {
return 'C';
}
}
// Sử dụng function
const grade1 = calculateGrade(85);
const grade2 = calculateGrade(92);
const grade3 = calculateGrade(76);
console.log('Học sinh 1:', grade1); // B
console.log('Học sinh 2:', grade2); // A
console.log('Học sinh 3:', grade3); // C
Dưới đây là các lỗi học sinh thường mắc phải và cách khắc phục:
// ❌ LỖI: Truy cập index không tồn tại
const fruits = ['táo', 'cam', 'xoài'];
console.log(fruits[5]); // undefined - không có index 5!
console.log(fruits[-1]); // undefined - không có index âm!
// ❌ LỖI: Dùng length làm index
console.log(fruits[fruits.length]); // undefined - vì length = 3, nhưng index cuối là 2
// ✅ ĐÚNG: Kiểm tra trước khi truy cập
if (fruits.length > 0) {
console.log('Phần tử đầu:', fruits[0]);
console.log('Phần tử cuối:', fruits[fruits.length - 1]);
}
// ✅ ĐÚNG: Dùng optional chaining (ES2020)
console.log(fruits[5] ?? 'Không tồn tại');
// ✅ ĐÚNG: Kiểm tra index hợp lệ
function getItem(arr, index) {
if (index >= 0 && index < arr.length) {
return arr[index];
}
return 'Index không hợp lệ';
}
// ❌ LỖI: Xóa phần tử trong vòng lặp for
const numbers = [1, 2, 3, 4, 5];
// KHÔNG làm thế này!
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1); // Xóa số chẵn - GÂY LỖI!
// Khi xóa, các phần tử sau sẽ dịch lên, làm bỏ sót
}
}
// ❌ LỖI: Thêm phần tử trong forEach
const items = [1, 2, 3];
items.forEach(item => {
items.push(item * 2); // Gây vòng lặp vô tận!
});
// ✅ ĐÚNG: Dùng filter để tạo array mới
const evenNumbers = numbers.filter(num => num % 2 === 0);
// ✅ ĐÚNG: Lặp ngược khi cần xóa
for (let i = numbers.length - 1; i >= 0; i--) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1);
}
}
// ✅ ĐÚNG: Tạo array mới thay vì sửa array cũ
const doubled = items.map(item => item * 2);
// ❌ LỖI: So sánh array bằng == hoặc ===
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = arr1;
console.log(arr1 === arr2); // false - Khác reference!
console.log(arr1 === arr3); // true - Cùng reference
// ❌ LỖI: Nghĩ rằng 2 array giống nhau sẽ bằng nhau
if (arr1 === arr2) { // Sẽ không bao giờ true!
console.log('Arrays bằng nhau');
}
// ✅ ĐÚNG: So sánh độ dài và từng phần tử
function arraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
// ✅ ĐÚNG: Dùng JSON.stringify cho array đơn giản
function simpleArraysEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
// ✅ ĐÚNG: Dùng every() method
function arraysEqualModern(a, b) {
return a.length === b.length &&
a.every((val, index) => val === b[index]);
}
Object có nhiều "cạm bẫy" mà học sinh thường gặp phải. Hãy tìm hiểu để tránh!
const user = {
name: 'John',
age: 25
};
// ❌ LỖI: Truy cập thuộc tính không tồn tại
console.log(user.email); // undefined - không có thuộc tính email
console.log(user.profile.avatar); // ERROR! - Cannot read property 'avatar' of undefined
// ❌ LỖI: Viết sai tên thuộc tính
console.log(user.Name); // undefined - phải là 'name' (chữ n thường)
console.log(user.AGE); // undefined - phải là 'age' (chữ thường)
// ✅ ĐÚNG: Kiểm tra thuộc tính tồn tại
if (user.email) {
console.log('Email:', user.email);
} else {
console.log('Không có email');
}
// ✅ ĐÚNG: Dùng optional chaining
console.log(user.profile?.avatar ?? 'Không có avatar');
// ✅ ĐÚNG: Dùng hasOwnProperty
if (user.hasOwnProperty('email')) {
console.log(user.email);
}
// ✅ ĐÚNG: Dùng in operator
if ('email' in user) {
console.log(user.email);
}
const scores = {
'math': 90,
'english': 85,
'science-lab': 95,
'2023-grade': 'A'
};
// ❌ LỖI: Dùng dot notation với tên có ký tự đặc biệt
console.log(scores.science-lab); // ERROR! Hiểu là phép trừ
console.log(scores.2023-grade); // ERROR! Không thể bắt đầu bằng số
// ❌ LỖI: Dùng bracket notation không đúng
const subject = 'math';
console.log(scores.subject); // undefined - tìm thuộc tính tên 'subject'
console.log(scores[subject]); // 90 - đúng, tìm thuộc tính tên trong biến subject
// ✅ ĐÚNG: Dùng bracket notation cho tên đặc biệt
console.log(scores['science-lab']); // 95
console.log(scores['2023-grade']); // 'A'
// ✅ ĐÚNG: Dùng biến làm key
const key = 'english';
console.log(scores[key]); // 85
// ✅ ĐÚNG: Dùng dot notation cho tên thường
console.log(scores.math); // 90
console.log(scores.english); // 85
Đây là lỗi gây ra nhiều bug nhất trong JavaScript. 90% học sinh mắc phải!
// ❌ LỖI NGUY HIỂM: Copy bằng reference
const originalArray = [1, 2, 3];
const originalObject = { name: 'John', score: 85 };
const copyArray = originalArray; // KHÔNG phải copy!
const copyObject = originalObject; // KHÔNG phải copy!
// Thay đổi "bản copy"
copyArray.push(4);
copyObject.score = 95;
// OMG! Bản gốc cũng bị thay đổi!
console.log(originalArray); // [1, 2, 3, 4] - BỊ THAY ĐỔI!
console.log(originalObject); // { name: 'John', score: 95 } - BỊ THAY ĐỔI!
// ✅ ĐÚNG: Shallow copy với spread operator
const realCopyArray = [...originalArray];
const realCopyObject = { ...originalObject };
realCopyArray.push(5);
realCopyObject.name = 'Jane';
console.log(originalArray); // [1, 2, 3] - KHÔNG bị thay đổi ✅
console.log(realCopyArray); // [1, 2, 3, 5] - Chỉ copy thay đổi ✅
// ⚠️ CHÚ Ý: Shallow copy chỉ copy 1 tầng
const nested = {
user: { name: 'John', age: 25 },
scores: [85, 90, 88]
};
const shallowCopy = { ...nested };
shallowCopy.user.age = 30; // Vẫn ảnh hưởng đến object gốc!
console.log(nested.user.age); // 30 - BỊ THAY ĐỔI!
// ✅ ĐÚNG: Deep copy cho nested object
const deepCopy = JSON.parse(JSON.stringify(nested));
// Hoặc dùng structuredClone() (modern browsers)
const modernDeepCopy = structuredClone(nested);
// ❌ LỖI: Mất context của this
const calculator = {
value: 0,
add: function(num) {
this.value += num;
return this;
},
getValue: function() {
return this.value;
}
};
// Lưu method vào biến
const add = calculator.add;
add(5); // ERROR! this không còn trỏ đến calculator
// ❌ LỖI: Dùng arrow function làm method
const brokenCalc = {
value: 0,
add: (num) => {
this.value += num; // ERROR! Arrow function không có this
}
};
// ✅ ĐÚNG: Dùng bind để giữ context
const boundAdd = calculator.add.bind(calculator);
boundAdd(5); // OK
// ✅ ĐÚNG: Gọi method trực tiếp từ object
calculator.add(10).add(5); // Method chaining
// ✅ ĐÚNG: Dùng call/apply
calculator.add.call(calculator, 3);
calculator.add.apply(calculator, [7]);
Đoạn code sau có nhiều lỗi nguy hiểm. Hãy tìm và sửa chúng:
// 🐛 BUGGY CODE - Tìm và sửa các lỗi sau:
const user = {
name: 'John',
'favorite-color': 'blue',
'2023-score': 95
};
// Lỗi 1: Truy cập thuộc tính không tồn tại
console.log(user.email.address); // ❌ Crash! Tại sao?
// Lỗi 2: Sai cách truy cập thuộc tính có dấu gạch ngang
console.log(user.favorite-color); // ❌ Lỗi syntax! Sửa thế nào?
// Lỗi 3: Truy cập thuộc tính bắt đầu bằng số
console.log(user.2023-score); // ❌ Lỗi syntax! Sửa thế nào?
// Lỗi 4: Copy object sai cách (nguy hiểm!)
const admin = user;
admin.name = 'Admin';
console.log(user.name); // ❌ Kết quả: 'Admin' - Tại sao user bị thay đổi?
// Lỗi 5: Nested object copy sai
const profile = {
info: { name: 'Jane', age: 25 },
settings: { theme: 'dark' }
};
const newProfile = { ...profile };
newProfile.info.age = 30;
console.log(profile.info.age); // ❌ Kết quả: 30 - Vẫn bị ảnh hưởng!
// Lỗi 6: This context bị mất
const calculator = {
value: 10,
add: function(x) { this.value += x; return this.value; }
};
const addFunc = calculator.add;
console.log(addFunc(5)); // ❌ Error hoặc kết quả không đúng
// TODO: Viết lại code đúng ở đây
// 1. Kiểm tra thuộc tính tồn tại trước khi truy cập
// 2. Dùng bracket notation cho thuộc tính đặc biệt
// 3. Copy object đúng cách (shallow và deep)
// 4. Giữ nguyên this context
Viết các function xử lý object một cách an toàn:
// TODO: Viết các utility function xử lý object an toàn
// 1. Function lấy giá trị an toàn (không crash khi thuộc tính không tồn tại)
function safeGet(obj, path, defaultValue = null) {
// TODO: Lấy giá trị từ path như 'user.profile.name'
// Trả về defaultValue nếu không tồn tại
// Ví dụ: safeGet({user: {name: 'John'}}, 'user.name') => 'John'
// safeGet({user: {}}, 'user.profile.name', 'Unknown') => 'Unknown'
}
// 2. Function deep copy object
function deepCopy(obj) {
// TODO: Copy object hoàn toàn (bao gồm cả nested objects và arrays)
// Không được dùng JSON.parse/stringify
}
// 3. Function merge objects an toàn
function safeMerge(target, source) {
// TODO: Gộp source vào target mà không làm thay đổi target gốc
// Trả về object mới
}
// 4. Function kiểm tra object rỗng
function isEmpty(obj) {
// TODO: Trả về true nếu object không có thuộc tính nào
// Xử lý cả null, undefined, array
}
// 5. Function so sánh deep equality
function deepEqual(obj1, obj2) {
// TODO: So sánh 2 object có giống nhau hoàn toàn không
// Bao gồm cả nested objects và arrays
}
// Test cases
const testObj = {
user: { name: 'John', age: 25 },
scores: [85, 90]
};
console.log(safeGet(testObj, 'user.name')); // Should: 'John'
console.log(safeGet(testObj, 'user.email', 'N/A')); // Should: 'N/A'
console.log(isEmpty({})); // Should: true
console.log(isEmpty({a: 1})); // Should: false
const copied = deepCopy(testObj);
copied.user.age = 30;
console.log(testObj.user.age); // Should: 25 (không đổi)
const cho giá trị không đổilet cho giá trị thay đổifunction tên(thamSố) { return kếtQuả; }tên(giáTrị)Thực hành nhiều hơn! Hãy tạo các project nhỏ để áp dụng kiến thức đã học: